import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import * as crypto from 'crypto'
import { lastValueFrom } from 'rxjs';
import { URL } from 'url';

import WxPay from 'wechatpay-node-v3'



@Injectable()
export class PaymentService {
    private wxJSapiUrl = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';
    static wxPay:WxPay;

    constructor(
        private httpService:HttpService,
        private configService:ConfigService
    ) {
        //PaymentService.wxPay = new WxPay()
    }

    wxchatCreateAuthorization(url:string, method:string, mchid:string, body:object|string, serialNo:string, privateKey:string, timeStamp:number) {
        const urlObj = new URL(url)
        let bodyParamsStr = ''
        if(body) {
            if(typeof body == 'object') {
                if(Object.keys(body).length > 0) {
                    bodyParamsStr = JSON.stringify(body)
                }
            }else {
                bodyParamsStr = body
            }
        }

        const nonceStr = this.generate()

        const signature = crypto.createSign('RSA-SHA256')
        .update(`${method}\n${urlObj.pathname}\n${timeStamp}\n${nonceStr}\n${bodyParamsStr}\n`)
        .sign(privateKey, 'base64')

        return `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",serial_no="${serialNo}",nonce_str="${nonceStr}",timestamp="${timeStamp}",signature="${signature}"`
    }

    async wechatPayment(params:{appid:string, mchid:string, orderNo:string; total:number; notifyUrl : string; openid:string; privateKey:string; serialNo:string; description? : string;}) {
        const postData = {
            mchid : params.mchid,
            appid : params.appid,
            notify_url : params.notifyUrl,
            out_trade_no : params.orderNo,
            description : params.description || '充值余额支付',
            amount : {
                total : params.total * 100
            },
            payer : {
                openid : params.openid
            }
        }

        const timeStamp = Math.floor((new Date()).getTime() / 1000)

        try {
            const response = await this.httpService.post(
                this.wxJSapiUrl, 
                postData,
                {
                    timeout : 10000,
                    headers : {
                        'Content-Type':'application/json',
                        'Accept':'application/json',
                        Authorization : this.wxchatCreateAuthorization(this.wxJSapiUrl, 'POST', params.mchid, postData, params.serialNo, params.privateKey, timeStamp)
                    }
                }
            )
    
            const { data } = await lastValueFrom(response)

            if(data.prepay_id) {

                const nonceStr = this.generate()

                return {
                    timeStamp : String(timeStamp),
                    nonceStr : nonceStr,
                    package : 'prepay_id=' + data.prepay_id,
                    signType : 'RSA',
                    paySign : crypto.createSign('RSA-SHA256')
                    .update(`${params.appid}\n${timeStamp}\n${nonceStr}\nprepay_id=${data.prepay_id}\n`)
                    .sign(params.privateKey, 'base64')
                }
            }


        } catch (error) {
            console.log(error)
        }

        return null
    }

    generate() {
        const str = 'QA2ZXSD1W7EDC6743VFRTG8BVN58FHY2YU6GCJ0MD9IKIOL5LP'
        const min = 0
        const max = str.length - 1

        let tmpStr = ''

        for(let i = 0; i < 32; i ++) {
            let index = Math.floor(Math.random() * (max - min)) + min
            tmpStr += str.charAt(index)
        }

        return tmpStr
    }
}
